#pragma once

//.#include "communicate.h"

#include "progmesh.h"
#include "xrSpherical.h"

#include "PropSlimTools.h"
#include "vbm.h"

#include "../xrlc_light/xruvpoint.h"
#include "../xrlc_light/base_basis.h"
#include "../xrlc_light/base_color.h"

struct OGF_Texture
{
	shared_str			name;
	b_texture*			pSurface;
};
typedef svector<OGF_Texture,3>		vecOGF_T;
typedef vecOGF_T::iterator			itOGF_T;

struct OGF;
struct OGF_Vertex
{
	Fvector				P;
	Fvector				N;			// normal
	base_basis			T;			// tangent
	base_basis			B;			// binormal
	base_color			Color;
	svector<Fvector2,2>	UV;

	BOOL				similar		(OGF* p, OGF_Vertex&	other);
	void				dump		(u32 id);
};
typedef xr_vector<OGF_Vertex>		vecOGF_V;
typedef vecOGF_V::iterator			itOGF_V;
typedef vecOGF_V::const_iterator	citOGF_V;
struct x_vertex						// "fast" geometry, 16b/vertex
{
	Fvector				P;
	x_vertex			(const OGF_Vertex& c)	{ P	= c.P; }
	BOOL				similar		(OGF* p, x_vertex&	other);
};
typedef xr_vector<x_vertex>			vec_XV;
typedef vec_XV::iterator			itXV;

#pragma pack(push,1)
struct OGF_Face
{
	u16			v[3];

	IC void			safe_replace(int what, int to)
	{
		if (v[0]==what) v[0]=to; else if (v[0]>what) v[0]-=1;
		if (v[1]==what) v[1]=to; else if (v[1]>what) v[1]-=1;
		if (v[2]==what) v[2]=to; else if (v[2]>what) v[2]-=1;
	}
	IC bool			Degenerate()
	{	return ((v[0]==v[1]) || (v[0]==v[2]) || (v[1]==v[2])); }
	IC bool			Equal(OGF_Face& F)
	{
		// Test for 6 variations
		if ((v[0]==F.v[0]) && (v[1]==F.v[1]) && (v[2]==F.v[2])) return true;
		if ((v[0]==F.v[0]) && (v[2]==F.v[1]) && (v[1]==F.v[2])) return true;
		if ((v[2]==F.v[0]) && (v[0]==F.v[1]) && (v[1]==F.v[2])) return true;
		if ((v[2]==F.v[0]) && (v[1]==F.v[1]) && (v[0]==F.v[2])) return true;
		if ((v[1]==F.v[0]) && (v[0]==F.v[1]) && (v[2]==F.v[2])) return true;
		if ((v[1]==F.v[0]) && (v[2]==F.v[1]) && (v[0]==F.v[2])) return true;
		return false;
	}
};
typedef xr_vector<OGF_Face>			vecOGF_F;
typedef vecOGF_F::iterator			itOGF_F;
typedef vecOGF_F::const_iterator	citOGF_F;
typedef OGF_Face					x_face;
#pragma pack(pop)

struct OGF;

struct OGF_Base
{
	int					iLevel;
	u16					Sector;
	BOOL				bConnected;

	Fbox				bbox;
	Fvector				C;
	float				R;

	OGF_Base(int _Level) {
		bbox.invalidate	();
		iLevel			= _Level;
		bConnected		= FALSE;
		Sector			= 0xffff;
	}

	IC BOOL				IsNode()	{ return iLevel; }

	virtual void		PreSave		(u32 tree_id)				{};
	virtual void		Save		(IWriter &fs);
	virtual void		GetGeometry	(xr_vector<Fvector> &RES)	= 0;
	void				CalcBounds	(); 
};
extern xr_vector<OGF_Base *>		g_tree;

struct OGF : public OGF_Base
{
	u32					material	;
	vecOGF_T			textures	;
/*
	vecOGF_V			vertices	;
	vecOGF_F			faces		;

	// fast-vertices
	vec_XV				x_vertices	;
	vecOGF_F			x_faces		;

	// Progressive
	FSlideWindowItem	m_SWI		;		// The records of the collapses.
	FSlideWindowItem	x_SWI		;		// The records of the collapses / fast-path
*/
	// for build only
	u32					dwRelevantUV	;
	u32					dwRelevantUVMASK;
/*
	u32					vb_id	,	xvb_id;
	u32					vb_start,	xvb_start;
	u32					ib_id	,	xib_id;
	u32					ib_start,	xib_start;
	u32					sw_id	,	xsw_id;
*/
	
	template <typename t_vertices>
	struct	ogf_container
	{
		t_vertices			vertices;
		vecOGF_F			faces	;
		FSlideWindowItem	m_SWI	;
		u32					vb_id	;
		u32					vb_start;
		u32					ib_id	;
		u32					ib_start;
		u32					sw_id	;
		ogf_container(): vb_id(-1), vb_start(-1), ib_id(-1), ib_start(-1), sw_id(-1){}
	};

	ogf_container	<vecOGF_V>	data;
	ogf_container	<vec_XV>	fast_path_data;

	OGF() : OGF_Base(0) {
		data.m_SWI.count			= 0;
		data.m_SWI.sw			= 0;
		data.m_SWI.reserved[0]	= 0;
		data.m_SWI.reserved[1]	= 0;
		data.m_SWI.reserved[2]	= 0;
		data.m_SWI.reserved[3]	= 0;
		dwRelevantUV		= 0;
		dwRelevantUVMASK	= 0;

		//vb_id=xvb_id=vb_start=xvb_start=ib_id=xib_id=ib_start=xib_start=sw_id=xsw_id=u32(-1);
	};
	~OGF(){
		xr_free			(data.m_SWI.sw);
	}

	BOOL				dbg_SphereContainsVertex	(Fvector& c, float R);

	u16					x_BuildVertex		(x_vertex&	V);
	void				x_BuildFace			(OGF_Vertex& V1, OGF_Vertex& V2, OGF_Vertex& V3, bool _tc_);
	u16					_BuildVertex		(OGF_Vertex& V1);
	void				_BuildFace			(OGF_Vertex& V1, OGF_Vertex& V2, OGF_Vertex& V3, bool _tc_ = true);

	void				adjacent_select		(xr_vector<u32>& dest, xr_vector<bool>& vmark, xr_vector<bool>& fmark);

	void				Optimize			();
	void				CalculateTB			();
	void				MakeProgressive		(float metric_limit);
	void				Stripify			();
	void				DumpFaces			();

	BOOL				progressive_test	()	{ return data.m_SWI.count;	}
	void				progressive_clear	()	{ 
		data.m_SWI.count		= 0;
		xr_free			(data.m_SWI.sw);
	}

	virtual void		PreSave			(u32 tree_id);
	virtual void		Save			(IWriter &fs);

//	void				Save_Cached		(IWriter &fs, ogf_header& H, BOOL bColors);

	void				Save_Normal_PM	(IWriter &fs, ogf_header& H, BOOL bColors);
	void				Load_Normal_PM	(IReader &fs, ogf_header& H, BOOL bColors);

//	void				Save_Progressive(IWriter &fs, ogf_header& H, BOOL bColors);

	virtual void		GetGeometry		(xr_vector<Fvector> &R)
	{
		for (xr_vector<OGF_Vertex>::iterator I=data.vertices.begin(); I!=data.vertices.end(); I++)
			R.push_back(I->P);
	}
};

struct OGF_Reference : public OGF_Base
{
	OGF*				model;

	u32					material;
	vecOGF_T			textures;

	u32					vb_id	;
	u32					vb_start;
	u32					ib_id	;
	u32					ib_start;
	u32					sw_id	;

	Fmatrix				xform;
	base_color_c		c_scale;
	base_color_c		c_bias;

	OGF_Reference() : OGF_Base(0) 
					{
						model	= 0;
					}

	virtual void		Save		(IWriter &fs);
	virtual void		GetGeometry	(xr_vector<Fvector> &R)
	{
		Fvector			P;
		for (xr_vector<OGF_Vertex>::iterator I=model->data.vertices.begin(); I!=model->data.vertices.end(); I++)
		{
			xform.transform_tiny	(P,I->P);
			R.push_back				(P);
		}
	}
};

struct OGF_Node : public OGF_Base
{
	xr_vector<u32>		chields;

	OGF_Node(int _L, u16 _Sector) : OGF_Base(_L) { Sector=_Sector; }

	void				AddChield	(u32 ID)
	{
		chields.push_back	(ID);
		OGF_Base*			P = g_tree[ID];
		R_ASSERT			(P->Sector == Sector);
		bbox.merge			(P->bbox);
		P->bConnected		= TRUE;
	}
	virtual void		Save		(IWriter &fs);
	virtual void		GetGeometry	(xr_vector<Fvector> &R)
	{
		for (xr_vector<u32>::iterator I=chields.begin(); I!=chields.end(); I++)
			g_tree[*I]->GetGeometry(R);
	}
};

struct	OGF_LOD		: public OGF_Node
{
	OGF_LOD(int _L, u16 _Sector) : OGF_Node(_L,_Sector) {};

	struct _vertex
	{
		Fvector			v;
		Fvector2		t;
		u32				c_rgb_hemi;	// rgb,hemi
		u8				c_sun;
	};
	struct _face
	{
		_vertex			v			[4];
	};

	_face				lod_faces	[8];
	u32					lod_Material;

	virtual void		Save		(IWriter &fs);
};

void set_status(char* N, int id, int f, int v);

extern OGF_Base*				g_TREE_ROOT		;
